#include "gnfindpathdbthread.h"
#include <QSqlError>
#include <QSqlQuery>
#include <QSqlRecord>
#include <QDebug>
#include "gnfindpaththread.h"

CNS_INIT(GnFindPathDBThread)
CNS_REGISTER_CNS_COM_FACTORY2(GnFindPathDBThread, CnsComponent)
CNS_INIT_END

void FindPathDBQThread::run()
{
    exec();
}

GnFindPathDBThread::GnFindPathDBThread() : DbQueryBaseThread(new FindPathDBQThread())
{

}

SysGnFindPathDBThread::SysGnFindPathDBThread()
{

}

void SysGnFindPathDBThread::f_initDbQueryThread(CnsComponentPtr com, QVariantHash& props, QScopedPointer<QThread>& thread)
{
    GnFindPathDBThreadPtr threadCom = com.staticCast<GnFindPathDBThread>();
    props["finish"] = false;
    threadCom->setProps(props);
    com->moveToThread(thread.data());
    connect(thread.data(), &QThread::started, com.data(), [this,com]()
    {
        bool ret;
        com->exec("query", QStringList(), Qt::AutoConnection, Q_RETURN_ARG(bool, ret), Q_ARG(CnsComponentPtr, com));

        if(!ret){
            stop(com);
        }
    }, Qt::AutoConnection);
    thread->start();
}

void SysGnFindPathDBThread::stop(CnsComponentPtr com)
{
    GnFindPathDBThread* thread = static_cast<GnFindPathDBThread*>(com.data());
    thread->getProps()["finish"] = true;
    thread->getWorkThread()->quit();
    thread->setDead(true);
    thread->exec("stopTimer");
    if(thread->isForceStop()){
        return;
    }
    emit thread->dbQueryThreadFinished(com);
}

static QSqlDatabase getDB(CnsComponentPtr com, const QString &dbID)
{
    const QString& dbUser = com->property("dbUser").toString();
    const QString& dbName = com->property("dbName").toString();
    int port = com->property("port").toInt();
    const QString& passwd = com->property("passwd").toString();
    const QString& hostName = com->property("hostName").toString();
    const QString& dbType = com->property("dbType").toString();
    QSqlDatabase db = QSqlDatabase::addDatabase(dbType, dbID);

    db.setPort(port);

    db.setHostName(hostName);
    db.setUserName(dbUser);
    db.setPassword(passwd);
    db.setDatabaseName(dbName);
    return db;
}

bool SysGnFindPathDBThread::query_b(CnsComponentPtr com, CnsComponentPtr gnFindPathDBThread)
{
    static ulong unique = 0;
    GnFindPathDBThreadPtr p = com.staticCast<GnFindPathDBThread>();
    QVariantHash &props = p->getProps();

    const QStringList &l = props["readSqlsAndSplit"].toStringList();
    if(l.size())
    {
        QString dbID = "DbQueriesThread"+QString::number(unique++);
        QSqlError err;
        QSqlDatabase db = getDB(com, dbID);

        if (db.open()) {
            QSqlQuery q(db);

            com->setProperty(dbID, "connectionName");

            if(q.exec(l[0])){
                GnFindPathThreadPtr pt = com->property("gnFindPathThread").value<GnFindPathThreadPtr>();
                while(q.next()){
                    const QSqlRecord & rec = q.record();
                    for(int i =0; i < rec.count(); i ++)
                    {
                        PathFilesInfo& pathFiles = pt->getFilterFilePaths()[rec.value(0).toString()];
                        pathFiles._files = rec.value(1).toString();
                        pathFiles._status = FilesInfoStatus::FINISH_PATH | FilesInfoStatus::FINISH_SAVETODB;
                    }
                }
                if(pt->getFilterFilePaths().find("/") == pt->getFilterFilePaths().end()){
                    pt->moveToThread(pt->getWorkThread().data());
                    pt->getWorkThread()->start();
                }
            } else
            {
                if(!q.exec(l[1]))//create table
                {
                    err = db.lastError();
                    qDebug() << "text="<<err.text() << "driverText=" \
                             << err.driverText() << "databaseText=" << err.databaseText();
                    props.insert("status", tr("query error"));
                    db.close();
                    return false;
                }
            }
        } else{
            QSqlQuery q;
            err = db.lastError();
            QString result;
            QTextStream(&result) <<"text="<<err.text() << "driverText=" \
                                  << err.driverText() << "databaseText=" << err.databaseText();
            CNSLOG_DEBUG(result);

            props.insert("status", tr("open error"));

        }
    }
    return true;
}

void SysGnFindPathDBThread::f_emitPushFilePaths(CnsComponentPtr com, const QVariantHash& props)
{
    saveToPathFilesTable(com, props["thread_com"].value<CnsComponentPtr>());
}

void SysGnFindPathDBThread::saveToPathFilesTable(CnsComponentPtr com, CnsComponentPtr thread_com)
{
    GnFindPathThreadPtr thread = thread_com.staticCast<GnFindPathThread>();
    PathFilesInfoMap &map = thread->getFilterFilePaths();
    PathFilesInfoMap::iterator it = map.find("/");
    bool isFinished = it != map.end() && it->_status & FilesInfoStatus::FINISH_SAVETODB;
    if(isFinished)
    {
        stop(com);
        return;
    }
    PathFilesInfoMap filterFilePaths;
    {
        QReadLocker(&thread->getReadWriteLock());
        for(PathFilesInfoMap::iterator it = map.begin(); it != map.end(); it++)
        {
            if(it.value()._status & FilesInfoStatus::FINISH_PATH &&
               !(it.value()._status & FilesInfoStatus::FINISH_SAVETODB))
            {
                filterFilePaths[it.key()] = it.value();
            }
        }
    }
    const QString &connectionName = com->property("connectionName").toString();
    QSqlDatabase db = QSqlDatabase::database(connectionName);
    if(!db.isOpen()){
        db = getDB(com, connectionName);
        db.open();
    }

    QVariantHash& props = thread->getProps();
    QSqlError err;
    if(db.isOpen()){
        QSqlQuery q(db);
        const QSSHASH& patterns = props["patterns"].value<QSSHASH>();
        QString insertSql = "INSERT INTO "+ patterns["@Table"] + " values('";

        for(PathFilesInfoMap::iterator it = filterFilePaths.begin(); it != filterFilePaths.end(); it++)
        {
            PathFilesInfo &value = it.value();
            QString sql = insertSql + it.key() + "','" + value._files+"');";
            if(!q.exec(sql))
            {
                err = db.lastError();
                qDebug() << "text="<<err.text() << "driverText=" \
                         << err.driverText() << "databaseText=" << err.databaseText();
                props.insert("status", sql+" error");
                continue;
            }
            map[it.key()]._status |= FilesInfoStatus::FINISH_SAVETODB;
        }
    } else{
        QSqlQuery q;
        err = db.lastError();
        QString result;
        QTextStream(&result) <<"text="<<err.text() << "driverText=" \
                              << err.driverText() << "databaseText=" << err.databaseText();
        CNSLOG_DEBUG(result);

        props.insert("status", "open error in saveDB");

    }

}
